package service

import (
	"context"

	"gitee.com/flycash/simple-im/internal/domain"
	"gitee.com/flycash/simple-im/internal/pkg/nickname"
	"gitee.com/flycash/simple-im/internal/repository"

	"github.com/gotomicro/ego/core/elog"
	"github.com/pkg/errors"
)

var ErrGenAnonymousUser = errors.New("GenAnonymousUserFailed")

type UserService interface {
	GenAnonymousUser(ctx context.Context) (domain.User, error)
	Info(ctx context.Context, id int64) (domain.User, error)
	AllInfoList(ctx context.Context, limit int, offset int) (int64, []domain.User, error)
	AllUsersInfo(ctx context.Context) ([]domain.User, error)
	InfoByIDs(ctx context.Context, ids []int64) ([]domain.User, error)
	UpdateNonSensitiveInfo(ctx context.Context, user domain.User) error
}

type userService struct {
	logger            *elog.Component
	nicknameGenerator nickname.Generator
	repo              repository.UserRepository
}

func NewUserService(repo repository.UserRepository) UserService {
	return &userService{
		logger: elog.EgoLogger.With(elog.FieldComponent("userService")),
		// nicknameGenerator 位于 user/internal/pkg 里, ioc 无法调用, 需要在这手动创建
		nicknameGenerator: nickname.NewGenerator(),
		repo:              repo,
	}
}

func (svc *userService) InfoByIDs(ctx context.Context, ids []int64) ([]domain.User, error) {
	return svc.repo.FindByIDs(ctx, ids)
}

func (svc *userService) GenAnonymousUser(ctx context.Context) (domain.User, error) {
	name := svc.nicknameGenerator.Generate()
	u := domain.User{Nickname: name}
	id, err := svc.repo.Create(ctx, u)
	if err != nil {
		svc.logger.Error("生成匿名用户失败", elog.FieldErr(err))
		return domain.User{}, ErrGenAnonymousUser
	}
	u.ID = id
	return domain.User{
		ID:       id,
		Nickname: name,
	}, nil
}

func (svc *userService) Info(ctx context.Context, id int64) (domain.User, error) {
	return svc.repo.FindByID(ctx, id)
}

func (svc *userService) AllUsersInfo(ctx context.Context) ([]domain.User, error) {
	return svc.repo.FindAll(ctx)
}

func (svc *userService) AllInfoList(ctx context.Context, limit, offset int) (int64, []domain.User, error) {
	return svc.repo.FindByLimitOffset(ctx, limit, offset)
}

func (svc *userService) UpdateNonSensitiveInfo(ctx context.Context, user domain.User) error {
	return svc.repo.Update(ctx, user)
}
